package com.devin.filter;

import com.alibaba.dubbo.common.extension.Activate;
import com.alibaba.dubbo.rpc.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.*;

@Activate
public class TPMonitorFilter implements Filter,Runnable {


    Map<String, List<MethodInfo>> methodTimes = new ConcurrentHashMap<>();

    public TPMonitorFilter() {
        // 每隔5s 打印线程
        Executors.newSingleThreadScheduledExecutor()
                .scheduleWithFixedDelay(this,5,5, TimeUnit.SECONDS);
        // 初始等待10s , 间隔60 执行一次
        Executors.newSingleThreadScheduledExecutor()
                .scheduleWithFixedDelay(new RemoveDataThread(methodTimes),10,60,TimeUnit.SECONDS);

    }

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        Result result = null;
        Long takeTime = 0L;
        try {
            Long startTime  = System.currentTimeMillis();
            result = invoker.invoke(invocation);
            if(result.getException() instanceof  Exception) {
                throw new Exception(result.getException());
            }
            takeTime = System.currentTimeMillis() - startTime;

        }catch (Exception e){
            e.printStackTrace();
            return result;
        }
        String metodName = invocation.getMethodName();
        List<MethodInfo> methodInfos = methodTimes.get(metodName);
        if(methodInfos == null){
            methodInfos = new ArrayList<>();
            methodTimes.put(metodName,methodInfos);
        }
        methodInfos.add(new MethodInfo(invocation.getMethodName(),takeTime,System.currentTimeMillis()));
        return result;
    }

    private long getTP(List<MethodInfo> methodInfos,double rate){

        List<MethodInfo> sortInfo = new ArrayList<>();

        long endTime = System.currentTimeMillis();
        long startTime = System.currentTimeMillis() - 6000;

        int length = methodInfos.size();
        for(int i=0;i<length;i++){
            MethodInfo methodInfo = methodInfos.get(i);
            if(methodInfo.getEndTime() >= startTime && methodInfo.getEndTime() <= endTime){
                sortInfo.add(methodInfo);
            }
        }

        if(sortInfo.size() ==0)
            return 0;

        sortInfo.sort(new Comparator<MethodInfo>() {
            @Override
            public int compare(MethodInfo o1, MethodInfo o2) {
                if(o1.getTime() > o2.getTime()){
                    return 1;
                }else if(o1.getTime() < o2.getTime()){
                    return -1;
                }else {
                    return 0;
                }
            }
        });
//        for (MethodInfo methodInfo:sortInfo) {
//            System.out.printf(methodInfo.getTime()+"-");
//        }
        int index = (int)(sortInfo.size()*rate);
        return sortInfo.get(index).getTime();
    }

    @Override
    public void run() {
        Date data = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String dataStr = sdf.format(data);
        for(Map.Entry<String,List<MethodInfo>> mehodInfos:methodTimes.entrySet()){
            System.out.println(dataStr + mehodInfos.getKey() +"的TP90: " + getTP(mehodInfos.getValue(),0.9)+"毫秒");
            System.out.println(dataStr + mehodInfos.getKey() +"的TP99: " + getTP(mehodInfos.getValue(),0.99) + "毫秒");
        }
        System.out.println("----------------------------------------");
    }
}
